<?php
/**
 * @link https://www.len168.com
 * @copyright Copyright (c) 2020/9/21 len168.com
 * @author toshcn <toshcn@foxmail.com>
 */

namespace common\models;

use Yii;
use yii\db\conditions\AndCondition;
use yii\db\StaleObjectException;

/**
 * 公共基础模型类
 * Class Carousel
 */
class BaseActiveRecord extends \yii\db\ActiveRecord
{
    /**
     * 获取表单第一个校验错误信息
     * @return string
     */
    public function getFirstErrorMessage()
    {
        $msg = '';
        if (is_array($this->errors)) {
            foreach ((array) $this->errors as $key => $error) {
                return $msg = $error[0];
            }
        }
        return $msg;
    }

    /**
     * 条件更新 类似updateAll 自动增加主键条件
     * @param  boolean $runValidation 是否验证
     * @param array $attributeNames 要更新的字段 null默认全部
     * @param array $condition 更新条件 必需是数组
     * @param array $params 参数绑定
     * @return int
     * @throws \Exception
     * @throws \Throwable
     */
    public function updateWhere($runValidation = true, $attributeNames = null, $condition = [], $params = [])
    {
        if ($runValidation && !$this->validate($attributeNames)) {
            Yii::info('Model not updated due to validation error.', __METHOD__);
            return false;
        }

        if (!$this->isTransactional(self::OP_UPDATE)) {
            return $this->updateWhereInternal($attributeNames, $condition, $params);
        }

        $transaction = static::getDb()->beginTransaction();
        try {
            $result = $this->updateWhereInternal($attributeNames, $condition, $params);
            if ($result === false) {
                $transaction->rollBack();
            } else {
                $transaction->commit();
            }

            return $result;
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw $e;
        } catch (\Throwable $e) {
            $transaction->rollBack();
            throw $e;
        }
    }

    /**
     * 条件更新 调用 Yii updateAll
     * @param $attributes 要更新的字段 null默认全部
     * @param array $condition 更新条件 必需是数组
     * @param array $params 参数绑定
     * @return int
     * @throws StaleObjectException
     * @throws \yii\db\Exception
     */
    private function updateWhereInternal($attributes, $condition = [], $params = [])
    {
        $values = $this->getDirtyAttributes($attributes);
        if (empty($values)) {
            return 0;
        }

        $keys = $this->getOldPrimaryKey(true);
        $lock = $this->optimisticLock();
        if ($lock !== null) {
            $values[$lock] = $this->$lock + 1;
            $keys[$lock] = $this->$lock;
        }

        // 组合主键条件
        // We do not check the return value of updateAll() because it's possible
        // that the UPDATE statement doesn't change anything and thus returns 0.
        $rows = static::updateAll($values, new AndCondition([
            $keys,
            $condition
        ]));

        if ($lock !== null && !$rows) {
            throw new StaleObjectException('The object being updated is outdated.');
        }

        if (isset($values[$lock])) {
            $this->$lock = $values[$lock];
        }

        return $rows;
    }
}